#pragma once

#include "Generics.h"
#include <winsock2.h>
#include <string>
#include <stdio.h>
#include <iostream>
#include <vector>


namespace DataFeeds{

	typedef enum {SocketFeed, StdFeed} FeedType;

	/*
	 * Exceptions
	 */

	class DFException : public Generic::Exception {
		std::string _message;
	public:
		std::string Message();
		DFException(std::string message);
	};

	class DFFeedLostException : public DFException {
	public:
		DFFeedLostException(std::string message);
	};

	class DFFeedUnavailableException : public DFException {
	public:
		DFFeedUnavailableException(std::string message);
	};

	/*
	 * Interfaces
	 */

	class IDataFeed {
	public:
		virtual std::string GetData(bool block) = 0;
		virtual void Reply (std::string) = 0;
		virtual void Close() = 0;
	};

	class IFeedFactory {
	public:
		virtual bool FeedAwaiting() = 0;
		virtual IDataFeed * GetFeed() = 0;
		virtual void Initialize(std::string opts) = 0;
	};

	/*
	 * Classes
	 */

	class FeedManager {
		short _feed_num;
		FeedType _TypeFromString(std::string type);
		IFeedFactory * _CreateFF(FeedType type, std::string opts);
		std::vector<IFeedFactory *> _factories;
		std::vector<bool> _enabled;
		short _ready;
		void _CheckReady();
	public:
		FeedManager();
		void EnableFeed(FeedType type);
		void EnableAllFeeds();
		void DisableFeed(FeedType type);
		IDataFeed * GetFeed();
		bool FeedReady();
	};

	class SocketFeedFactory : public IFeedFactory {
	public:
		bool FeedAwaiting();
		IDataFeed * GetFeed();
		WSADATA wsaData;
		WORD wVer ;
		int nRet ;
		WORD WSAEvent ;
		WORD WSAErr ;
		SOCKET hSock ;
		std::vector<SOCKET> socketConnected ;
		void Initialize(std::string opts);
		//Use this function when the server is closed
		void Destroy(std::string opts);
	};

	class StdFeedFactory : public IFeedFactory {
		bool _created;
	public:
		bool FeedAwaiting();
		IDataFeed * GetFeed();
		void Initialize(std::string opts);
	};

	class SocketDataFeed : public IDataFeed {
	public:
		SOCKET hClient;
		std::string GetData(bool block);
		void Reply (std::string response);
		SocketDataFeed( SOCKET client) {
			hClient = client;
		};
		void Close();
	};

	class StdDataFeed : public IDataFeed {
	public:
		std::string GetData(bool block);
		void Reply (std::string);
		void Close();
	};
}

